package cn.edu.usst.cs.pi2;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicLong;

class PiProcessor {
    private final String piFilePath;
    private final BlockingQueue<Task> taskQueue;
    private final AtomicLong position;
    private int numThreads;
    private final String targetNumber;
    private final int blockSize;
    private final int overlapSize;
    private final int numBlocks;
    private int occ=0;

    public PiProcessor(String piFilePath, int numThreads, String targetNumber, int blockSize, int overlapSize) {
        this.piFilePath = piFilePath;
        long fileSize = new File(piFilePath).length();
        System.out.printf("文件总长：%d\n",fileSize);
        this.numBlocks = (int) ((fileSize + overlapSize) / (blockSize - overlapSize));
        this.taskQueue = new ArrayBlockingQueue<>(numBlocks);
        this.position = new AtomicLong(0);
        this.numThreads = numThreads;
        this.targetNumber = targetNumber;
        this.blockSize = blockSize;
        this.overlapSize = overlapSize;
    }

    public void startProcessing() throws InterruptedException {
        // 边界检查
        long fileSize = new File(piFilePath).length();
        if (fileSize < 1) {
            throw new IllegalArgumentException("文件大小不能为零或负数。");
        }
        if (numThreads <= 0) {
            throw new IllegalArgumentException("线程数量必须大于零。");
        }
        if (fileSize < numThreads) {
            numThreads = 1;
        }

        for (int i = 0; i < numBlocks; i++) {
            long start = (long) i * (blockSize - overlapSize);
            int length = blockSize;
            if (i == numBlocks - 1) {
                length = (int) (fileSize - start);
            }
            taskQueue.put(new Task(start, length, targetNumber));
        }
        System.out.print("starting threads...\r");

        // 创建并启动多个线程
        for (int i = 0; i < numThreads; i++) {
            Thread thread = new Thread(this::processTask);
            thread.start();
        }

        // 等待所有任务完成
        for (int i = 0; i < numThreads; i++) {
            taskQueue.put(new Task(-1, -1, null));
        }
    }

    private void processTask() {
        try {
            while (true) {
                Task task = taskQueue.take();
                if (task.start == -1 && task.length == -1 && task.targetNumber == null) {
                    break;
                }
                processBlock(task.start, task.length, task.targetNumber);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    private void processBlock(long start, int length, String targetNumber) {
        try (RandomAccessFile file = new RandomAccessFile(piFilePath, "r")) {
            if (start >= 0) {
                file.seek(start);
//                System.out.printf("reading from %d to %d\n",start,start+length);
                byte[] buffer = new byte[length];
                file.read(buffer);
                String piData = new String(buffer);
                int position = KMP.search(piData, targetNumber);
                if (position!= -1) {
                    long globalPosition = position + start;
                    System.out.println(' '+"出现次数："+(++occ)+"目标字符串位置：" + globalPosition);
                }
            } else {
                // 处理起始位置为负数的情况，可以选择跳过这个任务或者记录错误
                System.out.println("Invalid start position: " + start);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}